package com.googlecode.lohr.parser.combinators.grammars;

import com.googlecode.lohr.parser.combinators.Grammar;
import com.googlecode.lohr.parser.combinators.MatchError;
import com.googlecode.lohr.parser.combinators.matcher.MatchContext;
import com.googlecode.lohr.parser.combinators.matcher.Matcher;
import com.googlecode.lohr.parser.combinators.matcher.common.BooleanMatcher;
import com.googlecode.lohr.parser.combinators.matcher.common.DecimalMatcher;
import com.googlecode.lohr.parser.combinators.matcher.common.DoubleMatcher;
import com.googlecode.lohr.parser.combinators.matcher.common.IntegerMatcher;
import com.googlecode.lohr.parser.combinators.matcher.common.NameMatcher;
import com.googlecode.lohr.parser.combinators.matcher.common.QuotedStringMatcher;
import com.googlecode.lohr.parser.combinators.matcher.common.WhitespaceMatcher;
import com.googlecode.lohr.parser.combinators.node.StringNode;

/**
 * A grammar for the Terse RDF Triple Language (Turtle) language.
 * @see http://www.w3.org/TeamSubmission/turtle/
 * 
 * @author Ted Stockwell
 */
public class TurtleGrammar extends Grammar
{
	public static final TurtleGrammar DEFINITION= new TurtleGrammar();
	
	/**
	 * Elements of this grammar
	 */
	public final Matcher lower = range('a', 'z');
	public final Matcher digit = range('0', '9');
	public final Matcher ws = longest(new WhitespaceMatcher());
	public final Matcher optws = opt(ws);
	public final Matcher name= longest(new NameMatcher());
	
	public final Matcher QUOTED_STRING= new QuotedStringMatcher();
	public final Matcher QNAME= seq(opt(name), string(":"), opt(name));
	public final Matcher NODE_ID= seq(string("_:"), name);
	public final Matcher PREFIX_NAME= choice(name);
	public final Matcher URIREF= longest(new URIRefMatcher());
	public final Matcher RESOURCE=longest(choice(URIREF, QNAME));
	public final Matcher SUBJECT=longest(choice(RESOURCE, NODE_ID, string("[]")));
	public final Matcher BASE=seq(string("@base"), ws, URIREF);
	public final Matcher PREFIX_ID=seq(string("@prefix"), ws, opt(PREFIX_NAME), string(":"), ws, URIREF);
	public final Matcher BOOL=new BooleanMatcher();
	public final Matcher DECIMAL=new DecimalMatcher();
	public final Matcher DOUBLE=new DoubleMatcher();
	public final Matcher INTEGER=new IntegerMatcher();
	public final Matcher DATATYPE_STRING=seq(QUOTED_STRING, string("^^"), RESOURCE);
	public final Matcher LANGUAGE=seq(rep(1, max, lower), rep(0, max, seq(string("-"), rep(1, max, choice(lower, digit)))));
	public final Matcher STRING=seq(QUOTED_STRING, opt(seq(string("@"), LANGUAGE)));
	public final Matcher LITERAL=longest(choice(STRING, DATATYPE_STRING, INTEGER, DOUBLE, DECIMAL, BOOL));
	public final Matcher OBJECT=longest(choice(RESOURCE, LITERAL, NODE_ID, string("[]")));
	public final Matcher OBJECT_LIST=seq(OBJECT, longest(rep(0, max, seq(optws, string(","), optws, OBJECT))));
	public final Matcher VERB=longest(choice(RESOURCE, string("a")));
	public final Matcher PREDICATE_VALUES=seq(VERB, ws, OBJECT_LIST);
	public final Matcher TRIPLES=seq(SUBJECT, ws, PREDICATE_VALUES, longest(rep(0, max, seq(optws, string(";"), optws, PREDICATE_VALUES))));
	public final Matcher DIRECTIVE=choice(PREFIX_ID, BASE);
	public final Matcher STATEMENT=seq(choice(DIRECTIVE, TRIPLES), optws, string("."));
	public final Matcher DOCUMENT=seq(optws, longest(rep(1, max, seq(STATEMENT, optws))));
	
	
	
	public static class URIRefMatcher extends Matcher 
	{
		@Override 
		public void match(MatchContext ctx, int start)
		{
			final String input= ctx.getInput();
			if (input.length() <= start || input.charAt(start) != '<') {
				ctx.matchError(this, start, new MatchError("Expected '<'", start));
			}
			else {
				int pos = input.indexOf('>', start);
				if (pos < 0) {
					ctx.matchError(this, start, new MatchError("Expected end of URI reference", start));
				}
				else {
					pos++;
					ctx.matchFound(this, start, new StringNode(this, start, pos, input.substring(start, pos)));
				}
			}
			ctx.matchComplete(this, start);
		}
		
		@Override
		public String getLabel()
		{
			return "URI reference";
		}
	}
	
	

	private TurtleGrammar() {
		init();
	}
}
